package org.feng.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
import java.util.Set;

/**
 * 记录请求，响应报文日志
 *
 * @author feng
 */
@Slf4j
public class LogRequestAndResponseFilter extends HttpFilter {
    private static final long serialVersionUID = 205621337254073166L;

    private final Set<String> skipLogUrl;

    public LogRequestAndResponseFilter(Set<String> skipLogUrl) {
        this.skipLogUrl = skipLogUrl;
    }

    @Override
    protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {

        // 不打印日志
        if(skipLog(request)) {
            // 继续执行请求链
            chain.doFilter(request, response);
            return;
        }

        // Wrapper 封装 Request 和 Response
        ContentCachingRequestWrapper cachingRequest = new ContentCachingRequestWrapper(request);
        ContentCachingResponseWrapper cachingResponse = new ContentCachingResponseWrapper(response);

        // 继续执行请求链
        chain.doFilter(cachingRequest, cachingResponse);

        /// 在请求完成后记录请求、响应日志

        String method = request.getMethod();

        String uri = request.getRequestURI();
        // 请求体
        byte[] requestContent = cachingRequest.getContentAsByteArray();

        // get请求处理，拼接url
        if ("get".equalsIgnoreCase(method)) {
            Map<String, String[]> parameterMap = request.getParameterMap();
            if (!CollectionUtils.isEmpty(parameterMap)) {
                StringBuilder sb = new StringBuilder("?");
                parameterMap.forEach((paramName, paramsArray) -> {
                    for (String val : paramsArray) {
                        if(sb.length() > 1) {
                            sb.append("&");
                        }
                        sb.append(paramName).append("=").append(val);
                    }
                });
                uri = uri + sb;
            }
        }
        log.info("Request => {} {} {}", method, uri, new String(requestContent));

        // 响应状态
        int status = response.getStatus();
        // 响应体
        byte[] responseContent = cachingResponse.getContentAsByteArray();
        log.info("Response <= {} {}", status, new String(responseContent));

        // 把缓存的响应数据，响应给客户端
        cachingResponse.copyBodyToResponse();
    }

    private boolean skipLog(HttpServletRequest request) {
        if (CollectionUtils.isEmpty(skipLogUrl)) {
            return false;
        }

        return skipLogUrl.stream().anyMatch(request.getRequestURI()::contains);

        /*// 跳过文件上传接口
        if (request.getRequestURI().contains("/upload")) {
            return true;
        }
        // 跳过文件下载接口
        if (request.getRequestURI().contains("/download")) {
            return true;
        }
        // 跳过静态资源
        if (request.getRequestURI().contains("/static")) {
            return true;
        }
        return false;*/
    }
}
